﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace EmptyWallGallery.Core.Utilities
{
    public static class ImageUtilities
    {
        /// <summary>
        /// A quick lookup for getting image encoders
        /// </summary>

        private static Dictionary<string, ImageCodecInfo> _mEncoders;

        /// <summary>
        /// Resize the image to the specified width and height.
        /// </summary>
        /// <param name="image">The image to resize.</param>
        /// <param name="width">The width to resize to.</param>
        /// <param name="height">The height to resize to.</param>
        /// <param name="copyright">Copyright</param>
        /// <returns>The resized image.</returns>
        public static Bitmap ResizeImage(Image image, int width, int height, string copyright)
        {
            //a holder for the result
            int newWidth;
            int newHeight;

            if (image.Width <= width)
            {
                newWidth = image.Width;
                newHeight = image.Height;
            }
            else
            {
                var dAspect = (double)image.Height / (double)image.Width;
                newWidth = width;
                newHeight = Convert.ToInt32(Math.Round(width * dAspect));
            }

            var result = new Bitmap(newWidth, newHeight);
            //use a graphics object to draw the resized image into the bitmap
            var graphics1 = Graphics.FromImage(result);
            //set the resize quality modes to high quality
            graphics1.CompositingQuality = CompositingQuality.HighQuality;
            graphics1.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics1.SmoothingMode = SmoothingMode.HighQuality;
            //draw the image into the target bitmap
            graphics1.DrawImage(image, 0, 0, result.Width, result.Height);
            if (!string.IsNullOrEmpty(copyright))
            {
                graphics1.DrawString(copyright, new Font("Arial", 10), new SolidBrush(Color.Blue),
                    // ReSharper disable PossibleLossOfFraction
                                   (image.Width * 60) / 100, (image.Height * 1) / 100);
                // ReSharper restore PossibleLossOfFraction
            }
            graphics1.Save();

            //return the resulting bitmap
            return result;
        }

        /// <summary> 
        /// Saves an image as a jpeg image, with the given quality 
        /// </summary> 
        /// <param name="path">Path to which the image would be saved.</param>
        /// <param name="bitmap"></param>
        /// <param name="quality">An integer from 0 to 100, with 100 being the 
        /// highest quality</param> 
        /// <exception cref="ArgumentOutOfRangeException">
        /// An invalid value was entered for image quality.
        /// </exception>
        public static bool SaveJpeg(string path, Bitmap bitmap, int quality)
        {
            try
            {
                //ensure the quality is within the correct range
                if ((quality < 0) || (quality > 100))
                {
                    //create the error message
                    var error = string.Format("Jpeg image quality must be between 0 and 100, with 100 being the highest quality.  A value of {0} was specified.", quality);
                    //throw a helpful exception
                    throw new ArgumentOutOfRangeException(error);
                }

                //create an encoder parameter for the image quality
                var qualityParam = new EncoderParameter(Encoder.Quality, quality);
                //get the jpeg codec
                var jpegCodec = GetEncoderInfo("image/jpeg");

                //create a collection of all parameters that we will pass to the encoder
                var encoderParams = new EncoderParameters(1);
                //set the quality parameter for the codec
                encoderParams.Param[0] = qualityParam;
                //save the image using the codec and the parameters
                bitmap.Save(path, jpegCodec, encoderParams);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public static bool ResizeImage(Stream stream, string path, int width, int height, string copyright)
        {
            return SaveJpeg(path, ResizeImage(Image.FromStream(stream), width, height, copyright), 80);
        }

        /// <summary> 
        /// Returns the image codec with the given mime type 
        /// </summary> 
        public static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            //do a case insensitive search for the mime type
            var lookupKey = mimeType.ToLower();

            //the codec to return, default to null
            ImageCodecInfo foundCodec = null;

            //if we have the encoder, get it to return
            if (Encoders.ContainsKey(lookupKey))
            {
                //pull the codec from the lookup
                foundCodec = Encoders[lookupKey];
            }

            return foundCodec;
        }

        /// <summary>
        /// A quick lookup for getting image encoders
        /// </summary>
        public static Dictionary<string, ImageCodecInfo> Encoders
        {
            //get accessor that creates the dictionary on demand
            get
            {
                //if the quick lookup isn't initialised, initialise it
                if (_mEncoders == null)
                {
                    _mEncoders = new Dictionary<string, ImageCodecInfo>();
                }

                //if there are no codecs, try loading them
                if (_mEncoders.Count == 0)
                {
                    //get all the codecs
                    foreach (var codec in ImageCodecInfo.GetImageEncoders())
                    {
                        //add each codec to the quick lookup
                        _mEncoders.Add(codec.MimeType.ToLower(), codec);
                    }
                }

                //return the lookup
                return _mEncoders;
            }
        }
    }
}
